//package com.dragons.dragonsvf.utils.image_compress;
//
//import org.apache.commons.io.IOUtils;
//import org.springframework.web.multipart.MultipartFile;
//
//import javax.imageio.ImageIO;
//import java.awt.*;
//import java.awt.image.BufferedImage;
//import java.io.*;
//import java.nio.file.Files;
//import java.nio.file.Path;
//import java.nio.file.Paths;
//import java.util.*;
//import java.util.List;
//import java.util.PriorityQueue;
//
///**
// * @author Dragons.G
// * @date 2025-03-18 20:31:32
// * @description 对图片进行压缩和解压缩
// */
//public class IMGCompress {
//    // 霍夫曼节点定义
//    private static class HuffmanNode implements Comparable<HuffmanNode> {
//        int frequency;
//        byte data;
//        HuffmanNode left, right;
//
//        public HuffmanNode(byte data, int frequency) {
//            this.data = data;
//            this.frequency = frequency;
//        }
//
//        public HuffmanNode(int frequency, HuffmanNode left, HuffmanNode right) {
//            this.frequency = frequency;
//            this.left = left;
//            this.right = right;
//        }
//
//        @Override
//        public int compareTo(HuffmanNode o) {
//            return this.frequency - o.frequency;
//        }
//    }
//
//    /**
//     * 霍夫曼压缩核心实现
//     */
//    private static class HuffmanCompressor {
//        // 生成频率表（网页1/2的统计方法）
//        private static Map<Byte, Integer> buildFrequencyMap(byte[] data) {
//            Map<Byte, Integer> freqMap = new HashMap<>();
//            for (byte b : data) {
//                freqMap.put(b, freqMap.getOrDefault(b, 0) + 1);
//            }
//            return freqMap;
//        }
//
//        // 构建霍夫曼树（网页6的优先队列实现）
//        private static HuffmanNode buildHuffmanTree(Map<Byte, Integer> freqMap) {
//            PriorityQueue<HuffmanNode> queue = new PriorityQueue<>();
//            freqMap.forEach((data, freq) ->
//                queue.add(new HuffmanNode(data, freq)));
//
//            while (queue.size() > 1) {
//                HuffmanNode left = queue.poll();
//                HuffmanNode right = queue.poll();
//                queue.add(new HuffmanNode(left.frequency + right.frequency, left, right));
//            }
//            return queue.poll();
//        }
//
//        // 生成编码表（递归实现）
//        private static void generateCodeTable(HuffmanNode node, String code, Map<Byte, String> codeTable) {
//            if (node.left == null && node.right == null) {
//                codeTable.put(node.data, code);
//                return;
//            }
//            generateCodeTable(node.left, code + "0", codeTable);
//            generateCodeTable(node.right, code + "1", codeTable);
//        }
//
//        // 压缩主方法（网页1/2/3的核心逻辑）
//        public static byte[] compress(byte[] data, int width, int height) { // 修改位置3：添加宽高参数
//            Map<Byte, Integer> freqMap = buildFrequencyMap(data);
//            HuffmanNode root = buildHuffmanTree(freqMap);
//            Map<Byte, String> codeTable = new HashMap<>();
//            generateCodeTable(root, "", codeTable);
//
//            // 构建压缩数据（带元数据头）
//            try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
//                 DataOutputStream dos = new DataOutputStream(bos)) {
//
//                // 写入元数据：宽高
//                dos.writeInt(width);    // 新增
//                dos.writeInt(height);   // 新增
//
//                // 1. 写入编码表
//                dos.writeInt(codeTable.size());
//                codeTable.forEach((b, code) -> {
//                    try {
//                        dos.writeByte(b);
//                        dos.writeUTF(code);
//                    } catch (IOException e) {
//                        throw new CompressionException("COMPRESS_WRITE_ERROR", e);
//                    }
//                });
//
//                // 2. 写入位流数据
//                StringBuilder encodedData = new StringBuilder();
//                for (byte b : data) {
//                    encodedData.append(codeTable.get(b));
//                }
//
//                // 处理位填充
//                int bitLength = encodedData.length();
//                int padding = (8 - (bitLength % 8)) % 8;
//                //encodedData.append("0".repeat(padding));
//                encodedData.append(new String(new char[padding]).replace("\0", "0"));
//
//                // 转换位流为字节
//                byte[] byteData = new byte[bitLength / 8 + (padding > 0 ? 1 : 0)];
//                for (int i = 0; i < encodedData.length(); i += 8) {
//                    String byteStr = encodedData.substring(i, Math.min(i + 8, encodedData.length()));
//                    byteData[i/8] = (byte) Integer.parseInt(byteStr, 2);
//                }
//
//                dos.writeInt(byteData.length);
//                dos.write(byteData);
//                dos.writeByte(padding);
//
//                return bos.toByteArray();
//            } catch (IOException e) {
//                throw new CompressionException("COMPRESS_ERROR", e);
//            }
//        }
//
//        // 解压实现（网页5的反向逻辑）
//        public static byte[] decompress(byte[] compressedData) {
//            try (ByteArrayInputStream bis = new ByteArrayInputStream(compressedData);
//                 DataInputStream dis = new DataInputStream(bis)) {
//
//                // 读取元数据：宽高
//                int originalWidth = dis.readInt();   // 新增
//                int originalHeight = dis.readInt();  // 新增
//
//                // 1. 读取编码表
//                int codeTableSize = dis.readInt();
//                Map<String, Byte> reverseCodeTable = new HashMap<>();
//                for (int i = 0; i < codeTableSize; i++) {
//                    byte data = dis.readByte();
//                    String code = dis.readUTF();
//                    reverseCodeTable.put(code, data);
//                }
//
//                // 2. 读取位流数据
//                int dataLength = dis.readInt();
//                byte[] byteData = new byte[dataLength];
//                dis.readFully(byteData);
//                int padding = dis.readByte();
//
//                // 3. 转换为位字符串
//                StringBuilder bitStream = new StringBuilder();
//                for (byte b : byteData) {
//                    bitStream.append(String.format("%8s", Integer.toBinaryString(b & 0xFF))
//                        .replace(' ', '0'));
//                }
//                bitStream.setLength(bitStream.length() - padding);
//
//                // 4. 解码位流
//                List<Byte> result = new ArrayList<>();
//                StringBuilder currentCode = new StringBuilder();
//                for (int i = 0; i < bitStream.length(); i++) {
//                    currentCode.append(bitStream.charAt(i));
//                    Byte data = reverseCodeTable.get(currentCode.toString());
//                    if (data != null) {
//                        result.add(data);
//                        currentCode.setLength(0);
//                    }
//                }
//
//                // 转换为字节数组
//                byte[] output = new byte[result.size()];
//                for (int i = 0; i < output.length; i++) {
//                    output[i] = result.get(i);
//                }
//                return output;
//            } catch (IOException e) {
//                throw new CompressionException("DECOMPRESS_ERROR", e);
//            }
//        }
//    }
//
//    /**
//     * 图片压缩入口方法（网页1/2/4的实现整合）
//     */
//    public static void compressImage(Object input, Object output, float quality) {
//        try {
//            // 输入适配（网页4的转换逻辑）
//            byte[] inputData = convertInput(input);
//
//            // 调整图片尺寸（网页1的等比缩放逻辑）
//            BufferedImage image = ImageIO.read(new ByteArrayInputStream(inputData));
//
//            //注释这部分代码 以保持原来的尺寸
////            if (image.getWidth() > 1024 || image.getHeight() > 1024) {
////                image = resizeImage(image, 1024, 1024);
////            }
//
//            // 获取像素数据
//            ByteArrayOutputStream bos = new ByteArrayOutputStream();
//            ImageIO.write(image, "png", bos);
//            byte[] pixelData = bos.toByteArray();
//
//            // 霍夫曼压缩
//            //byte[] compressed = HuffmanCompressor.compress(pixelData);
//            // 修改位置3：传递宽高
//            byte[] compressed = HuffmanCompressor.compress(pixelData, image.getWidth(), image.getHeight());
//
//            // 输出处理（网页4的适配逻辑）
//            writeOutput(output, compressed);
//        } catch (Exception e) {
//            throw new CompressionException("IMAGE_COMPRESS_ERROR", e);
//        }
//    }
//
//    /**
//     * 输入类型适配器（支持5种输入类型）
//     */
//    private static byte[] convertInput(Object input) {
//        try {
//            if (input instanceof File) {
//                return Files.readAllBytes(((File)input).toPath());
//            } else if (input instanceof MultipartFile) {
//                return ((MultipartFile)input).getBytes();
//            } else if (input instanceof InputStream) {
//                return IOUtils.toByteArray((InputStream)input);
//            } else if (input instanceof String) { // Base64
//                return Base64.getDecoder().decode((String)input);
//            } else if (input instanceof byte[]) {
//                return (byte[]) input;
//            }
//            throw new IllegalArgumentException("Unsupported input type");
//        } catch (IOException e) {
//            throw new CompressionException("INPUT_CONVERSION_ERROR", e);
//        }
//    }
//
//    /**
//     * 输出类型适配器（支持4种输出类型）
//     */
//    private static void writeOutput(Object output, byte[] data) {
//        try {
//            if (output instanceof OutputStream) {
//                ((OutputStream)output).write(data);
//            } else if (output instanceof File) {
//                Files.write(((File)output).toPath(), data);
//            } else if (output instanceof StringBuffer) { // Base64
//                ((StringBuffer)output).append(Base64.getEncoder().encodeToString(data));
//            } else if (output instanceof byte[]) {
//                System.arraycopy(data, 0, (byte[])output, 0, data.length);
//            }
//        } catch (IOException e) {
//            throw new CompressionException("OUTPUT_WRITE_ERROR", e);
//        }
//    }
//
//    /**
//     * 异常处理类（网页2/4的错误处理思路）
//     */
//    public static class CompressionException extends RuntimeException {
//        private final String errorCode;
//        private static final Map<String, String> ERROR_MAP = new HashMap<>();
//
//        static {
//            ERROR_MAP.put("INPUT_CONVERSION_ERROR", "输入格式转换失败");
//            ERROR_MAP.put("IMAGE_COMPRESS_ERROR", "图片压缩过程异常");
//        }
//
//        public CompressionException(String code, Throwable cause) {
//            super("[" + code + "] " + ERROR_MAP.getOrDefault(code, "未知错误"), cause);
//            this.errorCode = code;
//        }
//    }
//
//    // 视频压缩接口（网页5的FFmpeg集成）
//    public static void compressVideo(File input, File output, int crf) {
//        try {
//            ProcessBuilder pb = new ProcessBuilder(
//                "ffmpeg", "-i", input.getPath(),
//                "-c:v", "ffv1",
//                "-crf", String.valueOf(crf),
//                output.getPath()
//            );
//            Process process = pb.start();
//            process.waitFor();
//        } catch (Exception e) {
//            throw new CompressionException("VIDEO_COMPRESS_ERROR", e);
//        }
//    }
//
//    // 图片尺寸调整（网页1的双线性插值实现）
//    private static BufferedImage resizeImage(BufferedImage original, int targetWidth, int targetHeight) {
//        Image resized = original.getScaledInstance(targetWidth, targetHeight, Image.SCALE_SMOOTH);
//        BufferedImage output = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_INT_RGB);
//        Graphics2D g2d = output.createGraphics();
//        g2d.drawImage(resized, 0, 0, null);
//        g2d.dispose();
//        return output;
//    }
//
//
//    public static void main1(String[] args) {
//        String inputPath = "C:\\D-Files\\Belife\\Black_House\\qrcode_annotation\\src\\main\\java\\com\\dragons\\image_compress\\imgs\\原始.jpg";
//        String compressedPath = "compressed.bin"; // 霍夫曼压缩后的二进制数据文件
//        String decompressedPath = "decompressed.png"; // // 解压后的图片文件
//        /*
//        * 生成的.bin文件有什么作用？
//        答：该文件是经过霍夫曼编码压缩后的二进制数据，包含：
//
//        原始图片的宽高信息（前8字节）
//        霍夫曼编码表（用于解码）
//        压缩后的像素位流数据
//        问题2：如何验证无损压缩的正确性？
//        使用MD5校验：
//
//        java
//        String originalMD5 = DigestUtils.md5Hex(Files.readAllBytes(Paths.get(inputPath)));
//        String restoredMD5 = DigestUtils.md5Hex(Files.readAllBytes(Paths.get(decompressedPath)));
//        System.out.println("MD5一致性: " + originalMD5.equals(restoredMD5));
//        * */
//
//        try {
//            // 压缩阶段
//            File inputFile = new File(inputPath);
//            ByteArrayOutputStream compressedStream = new ByteArrayOutputStream();
//            IMGCompress.compressImage(inputFile, compressedStream, 0.8f);
//            Files.write(Paths.get(compressedPath), compressedStream.toByteArray());
//
//            // 解压阶段
//            byte[] decompressedData = HuffmanCompressor.decompress(compressedStream.toByteArray());
//
//            // 验证解压数据
//            BufferedImage image = ImageIO.read(new ByteArrayInputStream(decompressedData));
//            if (image == null) {
//                throw new RuntimeException("解压数据无效，无法生成图片");
//            }
//
//            // 保存为无损格式
//            ImageIO.write(image, "PNG", new File(decompressedPath));
//
//            // 校验文件完整性
//            System.out.println("压缩率: " +
//                (Files.size(Paths.get(compressedPath)) * 100 / Files.size(Paths.get(inputPath))) + "%");
//        } catch (Exception e) {
//            System.err.println("错误详情:");
//            e.printStackTrace();
//        }
//    }
//
//    public static void main(String[] args) {
//        String inputPath = "C:\\D-Files\\Belife\\Black_House\\qrcode_annotation\\src\\main\\java\\com\\dragons\\image_compress\\imgs\\原始.jpg";
//
//        try {
//            File inputFile = new File(inputPath);
//            Path parentDir = inputFile.toPath().getParent(); // 修改位置1：获取父目录
//
//            // 修改位置4：生成同目录文件路径
//            String compressedPath = parentDir + File.separator + "compressed_data.bin";
//            String decompressedPath = parentDir + File.separator + "restored_image.png";
//
//            // 压缩
//            ByteArrayOutputStream compressedStream = new ByteArrayOutputStream();
//            IMGCompress.compressImage(inputFile, compressedStream, 0.8f);
//            Files.write(Paths.get(compressedPath), compressedStream.toByteArray());
//
//            // 解压
//            byte[] decompressedData = HuffmanCompressor.decompress(compressedStream.toByteArray());
//            BufferedImage restoredImage = ImageIO.read(new ByteArrayInputStream(decompressedData));
//
//            // 保存恢复的图片到原始目录
//            ImageIO.write(restoredImage, "PNG", new File(decompressedPath));
//
//            System.out.println("压缩文件位置: " + compressedPath);
//            System.out.println("恢复图片位置: " + decompressedPath);
//            System.out.println("原始尺寸: " + restoredImage.getWidth() + "x" + restoredImage.getHeight());
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//    }
//}
